#pragma once
#include <string>
#include <array>
#include <vector>
#include <map>
#include <simple_enum.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/json.hpp>










struct Address
{
    std::string street{};
    std::string city{};
    std::string state{};
};


template<class Archive>
void serialize(Archive& archive,
               Address& m) {
    archive(cereal::make_nvp("street", m.street));
    archive(cereal::make_nvp("city", m.city));
    archive(cereal::make_nvp("state", m.state));
}


class Employee
{
public:
    enum class PerformanceRating: int8_t
    {
        Exceed = 0,
        Meet_Expectation = 1,
        PIP = 2,
    };


    struct PersonalInfo
    {
        std::string name{};
        Address address{};
        std::string phone{};
    };



    Employee(PersonalInfo person_info, std::string department, std::map<int64_t, PerformanceRating> year_to_perf)
        : m_person_info(std::move(person_info)),m_department(std::move(department)),m_year_to_perf(std::move(year_to_perf)){}
    // 默认构造函数 default constructor
    Employee() = default;
    // 拷贝构造函数 copy constructor
    Employee(const Employee&) = default;
    // 移动构造函数 move constructor
    Employee(Employee&&) = default;
    // 拷贝赋值运算符 copy assignment operator
    Employee& operator=(const Employee&) = default;
    // 移动赋值运算符 move assignment operator
    Employee& operator=(Employee&&) noexcept = default;
    // 析构函数 destructor
    ~Employee() = default; 
    
    inline const PersonalInfo & get_person_info() const { return m_person_info; }
    inline PersonalInfo& get_person_info_mutable() { return m_person_info; }
    inline void set_person_info(PersonalInfo person_info) { m_person_info = std::move(person_info); }

    inline const std::string & get_department() const { return m_department; }
    inline std::string& get_department_mutable() { return m_department; }
    inline void set_department(std::string department) { m_department = std::move(department); }

    inline const std::map<int64_t, PerformanceRating> & get_year_to_perf() const { return m_year_to_perf; }
    inline std::map<int64_t, PerformanceRating>& get_year_to_perf_mutable() { return m_year_to_perf; }
    inline void set_year_to_perf(std::map<int64_t, PerformanceRating> year_to_perf) { m_year_to_perf = std::move(year_to_perf); }


    template<class Archive>
    void serialize(Archive& archive) {
        archive(cereal::make_nvp("person_info", m_person_info));
        archive(cereal::make_nvp("department", m_department));
        archive(cereal::make_nvp("year_to_perf", m_year_to_perf));
    }

private:
    PersonalInfo m_person_info{};
    std::string m_department{};
    std::map<int64_t, PerformanceRating> m_year_to_perf{};
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<Employee::PerformanceRating> = std::array<std::string_view, 3>{
            "Exceed",
            "Meet_Expectation",
            "PIP",
        };

        template <>
        inline constexpr auto values_v<Employee::PerformanceRating> = std::array<int8_t, 3>{
            0,
            1,
            2,
        };

        template <>
        inline constexpr auto entries_v<Employee::PerformanceRating> = std::array<std::pair<std::string_view, int8_t>, 3>{
            std::pair<std::string_view, int8_t>("Exceed", 0),
            std::pair<std::string_view, int8_t>("Meet_Expectation", 1),
            std::pair<std::string_view, int8_t>("PIP", 2),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, Employee::PerformanceRating const & t )
{
    std::string str(simple_enum::enum_name<Employee::PerformanceRating>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, Employee::PerformanceRating & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<Employee::PerformanceRating>(sv).value();
}
} // namespace cereal


template<class Archive>
void serialize(Archive& archive,
               Employee::PersonalInfo& m) {
    archive(cereal::make_nvp("name", m.name));
    archive(cereal::make_nvp("address", m.address));
    archive(cereal::make_nvp("phone", m.phone));
}





